#include "os_lib.h"
#include "os_dbg.h"
#include "os_types.h"
#include "os_sched.h"
#include <stdarg.h>

/**
 * 计算字符串str的长度，但不包括终止空字符
 */
size_t os_strlen (const char *str) {
    os_param_failed(str == OS_NULL, 0);

    const char * s = str;
    while (*s != '\0') {
        s++;
    }

    return s - str;
}

/**
 * 字符串复制，最多复制前N字节
*/
char * os_strncpy (char *dest, const char *src, int size) {
    os_param_failed((dest == OS_NULL) || (src == OS_NULL) || (size == 0), OS_NULL);

    // 建立两个新的局部方便，方便随时观察dest和src原始值
    char *dest_c = dest;
    const char *src_c = src;

    while (size--) {
        char c;

        c = *dest_c++ = *src_c++;   // 复制后取最后的值
        if (c == '\0') {
            // 遇到结束符, 其余继续填充空
            while (size--) {
                *dest_c++ = '\0';
            }

            break;
        }
    }
    return (dest);
}

/**
 * 复制字符串
 * 逐个复制，直到遇到OS_NULL字符
 */
char * os_strcpy (char *dest, const char *src) {
    os_param_failed((dest == OS_NULL) || (src == OS_NULL), OS_NULL);

    while ((*dest++ = *src++) != 0) {}

    return dest;
}

/**
 * 字符串比较
 */
int os_strcmp(const char *str1, const char *str2) {
    os_param_failed((str1 == OS_NULL) && (str2 != OS_NULL), -1);
    os_param_failed((str1 != OS_NULL) && (str2 == OS_NULL), 1);
    os_param_failed((str1 == OS_NULL) && (str2 == OS_NULL), 0);

    char res;

    while ((res = *str1 - *str2) && *str1++ && *str2++) {
    }
    return res;
}

/**
 * 指定长度比较
 */
int os_strncmp(const char *str1, const char *str2, size_t num) {
    os_param_failed(num == 0, 0);
    os_param_failed((str1 == OS_NULL) && (str2 != OS_NULL), -1);
    os_param_failed((str1 != OS_NULL) && (str2 == OS_NULL), 1);
    os_param_failed((str1 == OS_NULL) && (str2 == OS_NULL), 0);

    uint8_t res;

    while ((res = *str1 - *str2) && *str1++ && *str2++ && --num) {
    }
    return res;
}

/**
 * 忽略大小写比较前n个字符
 */
int os_strncasecmp(const char *str1, const char *str2, size_t num) {
    os_param_failed(num == 0, 0);
    os_param_failed((str1 == OS_NULL) && (str2 != OS_NULL), -1);
    os_param_failed((str1 != OS_NULL) && (str2 == OS_NULL), 1);
    os_param_failed((str1 == OS_NULL) && (str2 == OS_NULL), 0);

    uint8_t res = *str1 - *str2;
    while ((res == 0) || (res == (uint8_t)('a' - 'A')) || (res == (uint8_t)('A' - 'a'))) {
        // 计数为0，停止比较
        if (--num == 0) {
            break;
        }

        res = *(++str1) - *(++str2);
    }
    return res;
}

/**
 * 忽略大小写的比较
 */
int os_strcasecmp(const char * str1, const char * str2) {
    os_param_failed((str1 == OS_NULL) && (str2 != OS_NULL), -1);
    os_param_failed((str1 != OS_NULL) && (str2 == OS_NULL), 1);
    os_param_failed((str1 == OS_NULL) && (str2 == OS_NULL), 0);

    char res = *str1 - *str2;

    // 完全相同，str1大小str2小写, str2小写str1大写
    while ((res == 0) || (res == (uint8_t)('a' - 'A')) || (res == (uint8_t)('A' - 'a'))) {
        res = *(++str1) - *(++str2);
    }

    return res;
}

/**
 * 查找字符串
 */
char * os_strchr(const char *str, int c) {
    os_param_failed(str == OS_NULL, OS_NULL);

    while (*str && (c != *str)) {
        str++;
    }
    return (*str == c) ? (char *)str : OS_NULL;
}

/**
 * 查找字符串
 */
char * os_strstr(const char * str1, const char * str2) {
    os_param_failed((str1 == OS_NULL) || (str2 == OS_NULL), OS_NULL);
    os_param_failed(*str2 == '\0', (char *)str1);

    // 从开头进行查找
    while (*str1) {
        const char * t_str1 = str1;
        const char * t_str2 = str2;

        // 比较字符串是否相同
        while (*t_str1 && *t_str2 && (*t_str1 == *t_str2)) {
            t_str1++;
            t_str2++;
        }

        // 如果全部相同，则返回
        if (*t_str2 == '\0') {
            return (char *)str1;
        }

        // 继续从str1下一字符比较
        str1++;
    }

    return OS_NULL;
}

/**
 * 分割字符串str中的令牌使用delimitrer分隔转换为一系列
 */
char * os_strtok(char *str, const char *delims) {
    static char* last_str = OS_NULL;   // 静态变量，指向上一次的位置

    // 只在第一次传输非NULL，用于进行初始化
    if (str) {
        last_str = str;
    }

    // 从开头逐个去查找，查到以delim中存在的字符
    while (*last_str) {
        const char * delm = delims;

        // 逐个进行比较，如果找到后立即退出
        while (*delm) {
            if (*last_str == *delm) {
                *last_str++ = '\0';
                return last_str;
            }

            // 不匹配，取下一字符
            delm++;
        }

        last_str++;
    }

    return *last_str ? last_str : OS_NULL;
}

/**
 * 对输入的字符串进行选项的解析
 */
int os_getopt(const char * str, const char *opt_str) {
    //static int optindex = 1;
    //static int argindex = 1;

/*
    if (argindex >= argc || argv[argindex][0] != '-') {
        return -1; // 没有更多选项或不是选项
    }

    char opt = argv[argindex][optindex++];
    const char *optptr = strchr(optstring, opt);

    if (optptr == NULL) {
        return '?'; // 未知选项
    }

    if (optptr[1] == ':') {
        // 选项需要参数
        if (optindex == 1) {
            if (argindex + 1 >= argc) {
                return '?'; // 参数不足
            }
            optarg = argv[++argindex];
        } else {
            optarg = &argv[argindex][optindex];
        }
        optindex = 1;
        argindex++;
    } else {
        // 选项不需要参数
        if (optindex == 1) {
            argindex++;
        }
        optarg = NULL;
    }

    return opt;
*/
    return 0;
}


/**
 * 内存填充
*/
void * os_memset (void * mem, int v, int count) {
    os_param_failed(mem == OS_NULL, OS_NULL);
    os_param_failed(count == 0, mem);

    char * c = (char *)mem;

    while (count--) {
        *c++ = v;
    }
    return mem;
}

/**
 * 内存复制
*/
void * os_memcpy (void * dest, const void * src, int count) {
    os_param_failed(dest == src, dest);
    os_param_failed(count == 0, dest);
    
    // 要考虑两块内存的位置是否有重叠，不然可能导致复制出现问题
    // dest在低地址，或者dest在后边但是完全超出src尾部
    if ((dest <= src) || ((uint8_t *)dest >= ((uint8_t *)src + count))) {
        uint8_t * dest_c = (uint8_t *)dest;
        const uint8_t * src_c = (const uint8_t *)src;
        
        // 从头部开始复制
        while (count--) {
            *dest_c++ = *src_c++;
        }
    } else {
        // 有重叠
        uint8_t * dest_c = (uint8_t *)dest + count - 1;
        const uint8_t * src_c = (const uint8_t *)src + count - 1;

        // 从尾部开始复制
        while (count--) {
            *dest_c-- = *src_c--;
        }
    }

    return dest;
}

/**
 * 进行内存比较
 */
int os_memcmp(const void* ptr1, const void* ptr2, size_t num) {
    os_param_failed(num == 0, 0);
    os_param_failed((ptr1 == OS_NULL) && (ptr2 != OS_NULL), -1);
    os_param_failed((ptr1 != OS_NULL) && (ptr2 == OS_NULL), 1);
    os_param_failed((ptr1 == OS_NULL) && (ptr2 == OS_NULL), 0);

    const uint8_t * uc1 = (const uint8_t *)ptr1;
    const uint8_t * uc2 = (const uint8_t *)ptr2;
    uint8_t res;

    while ((res = *uc1++ - *uc2++) && --num) {}
    return res;
}

/**
 * 格式化字符串到指定缓存中
 */
int os_sprintf(char *str, const char *fmt, ...) {
    va_list ap;

    // 不加限制
    va_start(ap, fmt);
    int cnt = os_vsnprintf(str, 0xFFFFFFFF, fmt, ap);
    va_end(ap);
    return cnt;
}

int os_snprintf(char *str, size_t size, const char *fmt, ...) {
    va_list ap;

    va_start(ap, fmt);
    int cnt = os_vsnprintf(str, size, fmt, ap);
    va_end(ap);
    return cnt;
}

/**
 * 格式化生成字符串
 */
int os_vsnprintf(char *str, size_t size, const char *fmt, va_list args) {
    os_param_failed(str == OS_NULL, 0);
    os_param_failed(size < 0, 0);
    os_param_failed(fmt == OS_NULL, 0);

    int count = 0;

    char c = *str;
    while ((count < size) && (c = *fmt++)) {
        // 非以%开头的普通字符，写入接收缓存
        if (c != '%') {
            *str++ = c;
            count++;
            continue;
        }

        // 以%开头的格式化字符串
        c = *fmt++;         // 跳过%号

        // 跳过其它区域，直接检查生成的类型
        switch (c) {
            case 'c': {
                // 普通字符
                if (count < size) {
                    *str++ = va_arg(args, int);
                    count++;
                }
                break;
            }
            case 's': {
                // 字符串
                char * s = va_arg(args, char *);
                while (*s && (count < size)) {
                    *str++ = *s++;
                    count++;
                }
                break;
            }
            case 'd': {
                // 整数转换
                int d = va_arg(args, int);
                if (d < 0) {
                    if (count < size) {
                        *str++ = '-';
                        count++;
                    }
                    d = -d;
                }
                // Convert integer to string and store it in buffer
                char temp[12]; // Assumes int is 32 bits
                int i = 0;
                do {
                    temp[i++] = '0' + d % 10;
                    d /= 10;
                } while (d);
                while (i > 0 && (count < size)) {
                    *str++ = temp[--i];
                    count++;
                }
                break;
            }
            default: {
                if (count + 2 < size) {
                    *str++ = '%';
                    *str++ = c;
                    count += 2;
                }
                break;
            }
        }
    }

    // 标记结束符
    *str = '\0';
    return count;
}

/**
 * 格式化打印字符串
 */
void os_printf (const char * fmt, ...) {    
    va_list args;

    va_start(args, fmt);

    const char * str = fmt;
    char c = *str;
    while ((c = *str++) != '\0') {
        // 非以%开头的普通字符，写入接收缓存
        if (c != '%') {
            os_putc(c);
            continue;
        }

        // 以%开头的格式化字符串
        c = *str++;         // 跳过%号

        // 跳过其它区域，直接检查生成的类型
        switch (c) {
            case 'c': {
                // 普通字符
                os_putc(c);
                break;
            }
            case 's': {
                // 字符串
                char * s = va_arg(args, char *);
                while (*s) {
                    os_putc(*s++);
                }
                break;
            }
            case 'u': {
                unsigned int d = va_arg(args, unsigned int);

                char temp[12];
                int i = 0;
                do {
                    temp[i++] = '0' + d % 10;
                    d /= 10;
                } while (d);

                while (i > 0) {
                    os_putc(temp[--i]);
                }
                break;
            }
            case 'd': {
                // 整数转换
                int d = va_arg(args, int);
                if (d < 0) {
                    os_putc('-');
                    d = -d;
                }

                char temp[12];
                int i = 0;
                do {
                    temp[i++] = '0' + d % 10;
                    d /= 10;
                } while (d);
                while (i > 0) {
                    os_putc(temp[--i]);
                }
                break;
            }
            default: {
                os_putc(c);
                break;
            }
        }
    }
    va_end(args);
}
